var EXPORTED_SYMBOLS = ["exports"];

var mixer = (function() {

  var scope = {};
  Components.utils.import("resource://gre/modules/Services.jsm", scope);

  var self = {};
  self.state = {};

  self.cleaners = [];

  self.log = function(msg) {
    scope.Services.console.logStringMessage(msg);    
  };
  
  self.serializer = Components.classes["@mozilla.org/xmlextras/xmlserializer;1"]
    .createInstance(Components.interfaces.nsIDOMSerializer);

  self.styleService = Components.classes["@mozilla.org/content/style-sheet-service;1"]
    .getService(Components.interfaces.nsIStyleSheetService);
  self.ioService = Components.classes["@mozilla.org/network/io-service;1"]
    .getService(Components.interfaces.nsIIOService);
 
  self.dumpDocument = function(document, regex) {
    var txt = self.serializer.serializeToString(document);
    var lines = txt.split(/\>/);
    lines.forEach(function(line) {
      if (line.match(regex)) {
        self.log(line+">");
      }
    });
  };

  self.prefManager = Components.classes["@mozilla.org/preferences-service;1"].getService(Components.interfaces.nsIPrefService);
  self.prefBranch = self.prefManager.getBranch("extensions.mixer.");

  self.prefWatcher = function(winn) {
    var watcher = {};

    watcher.winn = winn;
    watcher.settings = {};

    watcher.decodePref = function(pref, key) {
      var prefType = pref.getPrefType(key);
      if (prefType == pref.PREF_STRING) { return pref.getCharPref(key); }
      if (prefType == pref.PREF_BOOL) { return pref.getBoolPref(key); }
      if (prefType == pref.PREF_INT) { return pref.getIntPref(key); }
    };

    watcher.observe = function(aSubject, aTopic, aData) {
      self.log("PREFCHANGE");

      var detail = {settings: this.settings};

      if (aData) {
        this.settings[aData] = this.decodePref(aSubject, aData);

        self.log("POST: " + JSON.stringify(this.settings));

        detail.key = aData;
        detail.value = this.settings[aData];
      }

      this.sidebar = this.winn.document.querySelector('browser#sidebar');
        
      var evt = this.winn.document.createEvent("CustomEvent");
      evt.initCustomEvent("mixerConfig", true, false, detail);      
      this.sidebar.contentDocument.dispatchEvent(evt);
    };

    watcher.decodeBranch = function(branch) {
      var json = {};

      var that = this;
      branch.getChildList("",{}).forEach(function(key) {
        json[key] = that.decodePref(branch, key);       
      });    

      return json;
    };

    self.prefBranch.addObserver("", watcher, false);  
    watcher.settings = watcher.decodeBranch(self.prefBranch);
    
    return watcher;
  };


  self.emit = function(eventType, detail, target) {
    self.log('emit: ' + eventType + "|ON:" + target.nodeName + "|| WITH: " + JSON.stringify(detail));

    target = target || winn.document;
    detail = detail || {};

    var evt = target.ownerDocument.createEvent("CustomEvent");
    evt.initCustomEvent(eventType, true, false, detail);
    target.dispatchEvent(evt);            
  };

  self.on = function(eventType, callback, target) {
    self.log('on: ' + eventType + "|ON:" + target.nodeName);
    target = target || winn.document;

    target.addEventListener(eventType, callback, false);    
  };

  self.addWindow = function(winn) {
    //winn.setTimeout(function() { winn.alert('selfish'); }, 2000);

    winn.mixer = winn.mixer || {};
    this.cleaners.push(function() { delete winn.mixer; });

    winn.mixer.widgets = {};

    winn.mixer.watcher = new self.prefWatcher(winn);
    winn.mixer.watcher.observe();

    var document = winn.document;

    //self.dumpDocument(document, /context/i);

    var style = document.createProcessingInstruction("xml-stylesheet",
                                                     'href="chrome://mixer/skin/chrome.css" type="text/css"');   
    document.insertBefore(style, document.firstChild);
    this.cleaners.push(function() {
      document.removeChild(style);  
    });

    var navbar = document.getElementById("nav-bar-customization-target");
    if (navbar) { 
      var mixerButton = document.createElement("toolbarbutton"); //orig.cloneNode(true);

      mixerButton.setAttribute("tooltiptext", "Mixer");
      mixerButton.setAttribute("id", "mixer-button");
      mixerButton.className = ["toolbarbutton-1","mixer-widget"].join(" ");

      mixerButton.addEventListener("click", function(event) {
        if (event.button !== 0) { return; }
          
        winn.mixer.toggleMixerSidebar();
      }, false);
      // PROOF OF CONCEPT -- chrome to sidebar
      mixerButton.addEventListener("click", function(event) {
        if (event.button === 0) { return; }
          
        winn.mixer.sidebar = document.querySelector('browser#sidebar');
        
        var evt = document.createEvent("CustomEvent");
        evt.initCustomEvent("foobaz", true, false, {foo:'bazzle'});      
        winn.mixer.sidebar.contentDocument.dispatchEvent(evt);
        
        self.log('foobaz!');
        
        self.log('you clacked');
      }, false);
      // PROOF OF CONCEPT -- sidebar to chrome
      document.addEventListener("numnum", function(event) {
        var detail = event.detail;
        mixerButton.setAttribute("tooltiptext", detail.foo || "Boo!");
      }, false);

      //anchor.parentNode.insertBefore(mixerButton,anchor);
      navbar.appendChild(mixerButton);

      this.cleaners.push(function() {
        mixerButton.parentNode.removeChild(mixerButton);
        //mixerButton.detach();
      });

      winn.mixer.widgets.mixerButton = mixerButton;
    }

    var bcset = document.getElementById('mainBroadcasterSet');
    if (bcset) {
      var bc = document.createElement('broadcaster');
      bc.setAttribute('id', 'mixer-broadcaster');
      bc.setAttribute('label', "Mixer");
      bc.setAttribute('autoCheck', 'false');
      bc.setAttribute('type', 'checkbox');
      bc.setAttribute('group', 'sidebar');
      bc.setAttribute('sidebarurl', "chrome://mixer/content/html/sidebar.html");
      bc.setAttribute('sidebartitle', "Mixer sidebar");
      bc.setAttribute('oncommand', 'mixer.toggleMixerSidebar()');
      bcset.appendChild(bc);

      this.cleaners.push(function() { 
        bcset.removeChild(bc); 
      });

      winn.mixer.widgets.broadcast = bc;
    }   

    var menupopup = document.getElementById('viewSidebarMenu');
    if (menupopup) {
      let mi = document.createElement('menuitem');
      mi.setAttribute('id', 'mixer-menuitem');
      mi.setAttribute('key', 'mixer-key');
      mi.setAttribute('observes', 'mixer-broadcaster');
      menupopup.appendChild(mi);

      this.cleaners.push(function() { 
        menupopup.removeChild(mi); 
      });

      winn.mixer.widgets.menuitem = mi;
    }

    var contextMenu = document.querySelector("#contentAreaContextMenu");
    var menuitem = document.createElement("menuitem");
    menuitem.setAttribute("id", "mixer-context-item");
    menuitem.setAttribute("label", "Add to Mixer");
    contextMenu.insertBefore(menuitem, contextMenu.firstChild);
    this.cleaners.push(function() { contextMenu.removeChild(menuitem); });
    winn.mixer.widgets.contextItem = menuitem;

    var mi2 = contextMenu.querySelector('#mixer-context-item');
    
    contextMenu.addEventListener("popupshowing", function(event) {
      self.log("CONTEXT");
      //self.log(winn.gContextMenu.target.outerHTML);
      self.log(JSON.stringify(Object.keys(winn.gContextMenu)));
      
      self.state.target = null;

      var addToMixer = false;
      self.log('add: ' + addToMixer);
      var target = winn.gContextMenu.target;
      while (target !== null) {
        self.log("CHECK: " + (!!target.matches) + ":: " + target.outerHTML);
        if (! target.matches) {
          target.matches = target.mozMatchesSelector;
        }
        if (!! target.matches) {
          if (target.matches("*[itemprop]:not(.mixer-data), *[property]:not(.mixer-data)")) {
            addToMixer = true;
            self.state.target = target;
          }
        }
        target = target.parentNode;
        self.log('add: ' + addToMixer);
      }
      //addToMixer = addToMixer || winn.gContextMenu.onLink;
      self.log('add: ' + addToMixer + " :: " + JSON.stringify(menuitem.className));
      //menuitem.setAttribute("hidden", !addToMixer);

      menuitem.className = menuitem.className.replace(/mixer-enabled/g, '');
      if (addToMixer) {
        menuitem.className += ' mixer-enabled';
      }
      self.log('add2: ' + addToMixer + " :: " + JSON.stringify(menuitem.className));
      
   }, false);
    menuitem.addEventListener("click", function(event) {
      self.log("rightwards ho: " + self.state.target.outerHTML);

      winn.mixer.sidebar = document.querySelector('browser#sidebar');
        
      var evt = document.createEvent("CustomEvent");
      evt.initCustomEvent("mixerAdd", true, false, {attribute:self.state.target});      
      winn.mixer.sidebar.contentDocument.dispatchEvent(evt);
        
    }, false);

    winn.mixer.toggleMixerSidebar = function() {
        
      winn.toggleSidebar('mixer-broadcaster');
      var showing = (winn.mixer.widgets.broadcast.getAttribute("checked") === 'true');
      self.log('oh yeah: ' + showing);

      if (true) {
        self.emit('mixer-showing', {showing: showing}, winn.document.documentElement);
        return;
      }
    };

    self.on('mixer-showing', function(event) {
      var detail = event.detail;
      self.log("SHOWSHOW: " + JSON.stringify(detail));

      self.uri = self.uri || self.ioService.newURI("chrome://mixer/skin/wrap.css", null, null);

      if (! detail.showing) {
        document.documentElement.className = document.documentElement.className.replace(/mixer-showing/g, '');
        self.log('unclassed');
        try {
          if (self.styleService.sheetRegistered(self.uri, self.styleService.AGENT_SHEET)) {
            self.styleService.unregisterSheet(self.uri, self.styleService.AGENT_SHEET);
          }
        } catch (ee) { 
          self.log("EE: " + ee); 
        }        
        self.log('unreged');
      } else {
        document.documentElement.className += " mixer-showing";
        self.log('classed');
        try {
          if (! self.styleService.sheetRegistered(self.uri, self.styleService.AGENT_SHEET)) {
            self.styleService.loadAndRegisterSheet(self.uri, self.styleService.AGENT_SHEET);
          }
        } catch (ee) { 
          self.log("EE: " + ee); 
        }
        self.log('reged');

        winn.mixer.watcher.observe();
      }      
      
    }, document.documentElement);

    var appcontent = winn.document.getElementById('appcontent');
    appcontent.addEventListener('DOMContentLoaded', function(event) {
      self.log(event.type);
    }, false);
    
  };


  self.cleanup = function() {
    this.cleaners.forEach(function(cleanup) {
      cleanup.call(this);
    });
    this.cleaners = [];
  };            

  self.init = function() {
  };

  return self;
}());

var exports = mixer;
